/*
 * @(#)SmartSolver.java    Jul 19, 2010
 *
 * Copyright 2009 Nyber Shanghai, Inc. All rights reserved.
 */

package com.lab.util.concurrent;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

/**
 * 1. 充分利用cpu, 就是有多少核心开多少线程参与计算.
 * 2. 无限大List, 无限大说明当前jvm内存可能不太够了, 计算中尽量少new对象.
 * 3. 无限大List, 无限大说明 极有可能产生非常大的 和数 需要考虑精度范围.
 * 
 * 为了保证精度因此使用了BigDecimal存储和数
 * 为了保证尽量少new BigDecimal对象, 每一个线程内部使用long进行求和, 
 * 	只有当精度不够时才加入到最终结果中, 同时内部和数置为合适数据, 线程结束时把内部和数加入最终结果
 *
 * @author nickevin@gmail.com
 * @version Jul 19, 2010 1:53:34 PM
 */

public class SmartSolver extends Thread {

    private List<Integer> list;
    private int start, end;
    private long value;
    private Result result;

    public SmartSolver(List<Integer> list, Integer start, Integer end,
            Result result) {
        this.list = list;
        this.start = start;
        this.end = end;
        this.result = result;
    }

    private void add(int v) {
        if (Long.MAX_VALUE - v > value) {
            value += v;
        } else {
            result.addSum(value);
            value = v;
        }
    }

    @Override
    public void run() {
        try {
            for (int i = start; i < end; i++) {
                add(list.get(i));
            }
            result.addSum(value);
        } finally {
            result.finishA();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        List<Integer> list = new ArrayList<Integer>();
        for (int i = 0; i < 100000; i++) {
            list.add(i);
        }

        Result result = new Result();

        int cpuCoreSize = Runtime.getRuntime().availableProcessors();
        int len = list.size() / cpuCoreSize;
        if (len == 0) {
            len = 1;
        }
        int start = 0, end = len;

        List<Thread> threads = new ArrayList<Thread>();
        for (;;) {
            end = start + len;
            if (end > list.size()) {
                end = list.size();
            }
            threads.add(new SmartSolver(list, start, end, result));
            start = end;
            if (start == list.size()) {
                break;
            }
        }
        result.setCountThread(threads.size());

        for (Thread thread : threads) {
            thread.start();
        }

        synchronized (result) {
            while (!result.isGameOver()) {
                result.wait();
            }
        }
        System.out.println("和为：" + result.getSum());
    }
}

class Result {

    private BigDecimal sum;
    private int countFinish, countThread;

    public BigDecimal getSum() {
        return sum;
    }

    public void setCountThread(int countThread) {
        assert countThread > 0;
        this.countThread = countThread;
    }

    private void checkGameOver() {
        if (isGameOver()) {
            notifyAll();
        }
    }

    public synchronized boolean isGameOver() {
        return countFinish >= countThread;
    }

    public synchronized void addSum(long v) {
        sum = sum == null ? new BigDecimal(v) : sum.add(BigDecimal.valueOf(v));
    }

    public synchronized void finishA() {
        countFinish++;
        checkGameOver();
    }
}
